﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Skyhook.Core.Graphics;
using Skyhook.Core;
using System.IO;

namespace Skyhook.Resources
{
    internal class ImageCollectionLoader
    {
        const int MaxTextureWidth = 4096;
        const int MaxTextureHeigth = 4096;

        int[] AdressTable = null;
        int[] Dx = null;
        int[] Dy = null;
        int[] Width = null;
        int[] Height = null;

        Rectangle[] FrameRects = null;
        Vector2[] CenterPoints = null;
        Texture2D Texture = null;

        int ImagesNumber = 0;

        public void LoadFromFile(string filename, out Texture2D texture, out Rectangle[] framerects, out Vector2[] centerpoints)
        {
            Stream input = StreamFactory.CreateGZip(filename);
            BinaryReader reader = new BinaryReader(input);

            ReadAdressTable(reader);
            ReadImagesParameters(reader);
            Rectangle bounds = CalculateFrameRectsAndCenterPoints();
            Texture = GraphicsFactory.CreateTexture2D(bounds.Width, bounds.Height);
            ReadImagesAndSaveToTexture(reader);

            reader.Close();
            input.Close();

            texture = Texture;
            framerects = FrameRects;
            centerpoints = CenterPoints;
        }

        void ReadAdressTable(BinaryReader reader)
        {
            reader.BaseStream.Seek(0, SeekOrigin.Begin);

            ImagesNumber = reader.ReadInt32();
            AdressTable = new int[ImagesNumber];

            for (int i = 0; i < ImagesNumber; i++)
            {
                AdressTable[i] = reader.ReadInt32();
            }
        }

        void ReadImagesParameters(BinaryReader reader)
        {
            Dx = new int[ImagesNumber];
            Dy = new int[ImagesNumber];
            Width = new int[ImagesNumber];
            Height = new int[ImagesNumber];
            CenterPoints = new Vector2[ImagesNumber];
            FrameRects = new Rectangle[ImagesNumber];

            for (int i = 0; i < ImagesNumber; i++)
            {
                reader.BaseStream.Seek(AdressTable[i], SeekOrigin.Begin);
                Dx[i] = reader.ReadInt32();
                Dy[i] = reader.ReadInt32();
                Width[i] = reader.ReadInt32();
                Height[i] = reader.ReadInt32();
            }
        }

        void ReadImagesAndSaveToTexture(BinaryReader reader)
        {
            for (int i = 0; i < ImagesNumber; i++)
            {
                ReadSingleImageAndSaveToTexture(reader, i);
            }
        }

        void ReadSingleImageAndSaveToTexture(BinaryReader reader, int texturenum)
        {
            reader.BaseStream.Seek(AdressTable[texturenum] + 17, SeekOrigin.Begin);
            Color[] image = new Color[Width[texturenum] * Height[texturenum]];
            for (int y = 0; y < Height[texturenum]; y++)
            {
                int strlen = reader.ReadInt16();
                int nums = 0;
                int cx = 0;
                while (nums < strlen)
                {
                    byte param = reader.ReadByte();
                    nums++;
                    if ((param & 0x80) == 0x80)
                    {
                        cx += param - 0x80;
                    }
                    else
                    {
                        for (int j = 0; j < param; j++)
                        {
                            image[cx + y * Width[texturenum]].R = reader.ReadByte();
                            image[cx + y * Width[texturenum]].G = reader.ReadByte();
                            image[cx + y * Width[texturenum]].B = reader.ReadByte();
                            image[cx + y * Width[texturenum]].A = reader.ReadByte();
                            cx++;
                            nums += 4;
                        }
                    }
                }
            }
            Texture.SetData<Color>(0, FrameRects[texturenum], image, 0, Width[texturenum] * Height[texturenum]);
        }        

        Rectangle CalculateFrameRectsAndCenterPoints()
        {
            Rectangle result = new Rectangle();
            result.X = 0;
            result.Y = 0;
            result.Width = 0;
            result.Height = 0;

            int totalwidth = Width.Sum();
            int rowheight = Height.Max();

            int row = 0;
            int rowwidth = 0;
            for (int i = 0; i < Width.Length; i++)
            {
                if (rowwidth + Width[i] > MaxTextureWidth)
                {
                    if (rowwidth > result.Width)
                    {
                        result.Width = rowwidth;
                    }
                    row++;
                    rowwidth = 0;
                }
                FrameRects[i] = new Rectangle(rowwidth, row * rowheight, Width[i], Height[i]);
                CenterPoints[i] = new Vector2(-Dx[i], -Dy[i]);
                rowwidth += Width[i];
            }
            if (rowwidth > result.Width)
            {
                result.Width = rowwidth;
            }

            result.Height = rowheight * (row + 1);

            return result;
        }
    }
}
